home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / gfx / conv / jpegV5Asrc.lha / jpeg-5a / rdppm.c < prev    next >
C/C++ Source or Header  |  1994-11-11  |  14KB  |  451 lines

  1. /*
  2.  * rdppm.c
  3.  *
  4.  * Copyright (C) 1991-1994, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains routines to read input images in PPM/PGM format.
  9.  * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
  10.  * The PBMPLUS library is NOT required to compile this software
  11.  * (but it is highly useful as a set of PPM image manipulation programs).
  12.  *
  13.  * These routines may need modification for non-Unix environments or
  14.  * specialized applications.  As they stand, they assume input from
  15.  * an ordinary stdio stream.  They further assume that reading begins
  16.  * at the start of the file; start_input may need work if the
  17.  * user interface has already read some data (e.g., to determine that
  18.  * the file is indeed PPM format).
  19.  */
  20.  
  21. #include "cdjpeg.h"        /* Common decls for cjpeg/djpeg applications */
  22.  
  23. #ifdef PPM_SUPPORTED
  24.  
  25.  
  26. /* Portions of this code are based on the PBMPLUS library, which is:
  27. **
  28. ** Copyright (C) 1988 by Jef Poskanzer.
  29. **
  30. ** Permission to use, copy, modify, and distribute this software and its
  31. ** documentation for any purpose and without fee is hereby granted, provided
  32. ** that the above copyright notice appear in all copies and that both that
  33. ** copyright notice and this permission notice appear in supporting
  34. ** documentation.  This software is provided "as is" without express or
  35. ** implied warranty.
  36. */
  37.  
  38.  
  39. /* Macros to deal with unsigned chars as efficiently as compiler allows */
  40.  
  41. #ifdef HAVE_UNSIGNED_CHAR
  42. typedef unsigned char U_CHAR;
  43. #define UCH(x)    ((int) (x))
  44. #else /* !HAVE_UNSIGNED_CHAR */
  45. #ifdef CHAR_IS_UNSIGNED
  46. typedef char U_CHAR;
  47. #define UCH(x)    ((int) (x))
  48. #else
  49. typedef char U_CHAR;
  50. #define UCH(x)    ((int) (x) & 0xFF)
  51. #endif
  52. #endif /* HAVE_UNSIGNED_CHAR */
  53.  
  54.  
  55. #define    ReadOK(file,buffer,len)    (JFREAD(file,buffer,len) == ((size_t) (len)))
  56.  
  57.  
  58. /*
  59.  * On most systems, reading individual bytes with getc() is drastically less
  60.  * efficient than buffering a row at a time with fread().  On PCs, we must
  61.  * allocate the buffer in near data space, because we are assuming small-data
  62.  * memory model, wherein fread() can't reach far memory.  If you need to
  63.  * process very wide images on a PC, you might have to compile in large-memory
  64.  * model, or else replace fread() with a getc() loop --- which will be much
  65.  * slower.
  66.  */
  67.  
  68.  
  69. /* Private version of data source object */
  70.  
  71. typedef struct {
  72.   struct cjpeg_source_struct pub; /* public fields */
  73.  
  74.   U_CHAR *iobuffer;        /* non-FAR pointer to I/O buffer */
  75.   JSAMPROW pixrow;        /* FAR pointer to same */
  76.   size_t buffer_width;        /* width of I/O buffer */
  77.   JSAMPLE *rescale;        /* => maxval-remapping array, or NULL */
  78. } ppm_source_struct;
  79.  
  80. typedef ppm_source_struct * ppm_source_ptr;
  81.  
  82.  
  83. LOCAL int
  84. pbm_getc (FILE * infile)
  85. /* Read next char, skipping over any comments */
  86. /* A comment/newline sequence is returned as a newline */
  87. {
  88.   register int ch;
  89.  
  90.   ch = getc(infile);
  91.   if (ch == '#') {
  92.     do {
  93.       ch = getc(infile);
  94.     } while (ch != '\n' && ch != EOF);
  95.   }
  96.   return ch;
  97. }
  98.  
  99.  
  100. LOCAL unsigned int
  101. read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
  102. /* Read an unsigned decimal integer from the PPM file */
  103. /* Swallows one trailing character after the integer */
  104. /* Note that on a 16-bit-int machine, only values up to 64k can be read. */
  105. /* This should not be a problem in practice. */
  106. {
  107.   register int ch;
  108.   register unsigned int val;
  109.  
  110.   /* Skip any leading whitespace */
  111.   do {
  112.     ch = pbm_getc(infile);
  113.     if (ch == EOF)
  114.       ERREXIT(cinfo, JERR_INPUT_EOF);
  115.   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
  116.  
  117.   if (ch < '0' || ch > '9')
  118.     ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
  119.  
  120.   val = ch - '0';
  121.   while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
  122.     val *= 10;
  123.     val += ch - '0';
  124.   }
  125.   return val;
  126. }
  127.  
  128.  
  129. /*
  130.  * Read one row of pixels.
  131.  *
  132.  * We provide several different versions depending on input file format.
  133.  * In all cases, input is scaled to the size of JSAMPLE.
  134.  *
  135.  * A really fast path is provided for reading byte/sample raw files with
  136.  * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
  137.  */
  138.  
  139.  
  140. METHODDEF JDIMENSION
  141. get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  142. /* This version is for reading text-format PGM files with any maxval */
  143. {
  144.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  145.   FILE * infile = source->pub.input_file;
  146.   register JSAMPROW ptr;
  147.   register JSAMPLE *rescale = source->rescale;
  148.   JDIMENSION col;
  149.  
  150.   ptr = source->pub.buffer[0];
  151.   for (col = cinfo->image_width; col > 0; col--) {
  152.     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
  153.   }
  154.   return 1;
  155. }
  156.  
  157.  
  158. METHODDEF JDIMENSION
  159. get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  160. /* This version is for reading text-format PPM files with any maxval */
  161. {
  162.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  163.   FILE * infile = source->pub.input_file;
  164.   register JSAMPROW ptr;
  165.   register JSAMPLE *rescale = source->rescale;
  166.   JDIMENSION col;
  167.  
  168.   ptr = source->pub.buffer[0];
  169.   for (col = cinfo->image_width; col > 0; col--) {
  170.     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
  171.     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
  172.     *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
  173.   }
  174.   return 1;
  175. }
  176.  
  177.  
  178. METHODDEF JDIMENSION
  179. get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  180. /* This version is for reading raw-byte-format PGM files with any maxval */
  181. {
  182.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  183.   register JSAMPROW ptr;
  184.   register U_CHAR * bufferptr;
  185.   register JSAMPLE *rescale = source->rescale;
  186.   JDIMENSION col;
  187.  
  188.   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
  189.     ERREXIT(cinfo, JERR_INPUT_EOF);
  190.   ptr = source->pub.buffer[0];
  191.   bufferptr = source->iobuffer;
  192.   for (col = cinfo->image_width; col > 0; col--) {
  193.     *ptr++ = rescale[UCH(*bufferptr++)];
  194.   }
  195.   return 1;
  196. }
  197.  
  198.  
  199. METHODDEF JDIMENSION
  200. get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  201. /* This version is for reading raw-byte-format PPM files with any maxval */
  202. {
  203.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  204.   register JSAMPROW ptr;
  205.   register U_CHAR * bufferptr;
  206.   register JSAMPLE *rescale = source->rescale;
  207.   JDIMENSION col;
  208.  
  209.   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
  210.     ERREXIT(cinfo, JERR_INPUT_EOF);
  211.   ptr = source->pub.buffer[0];
  212.   bufferptr = source->iobuffer;
  213.   for (col = cinfo->image_width; col > 0; col--) {
  214.     *ptr++ = rescale[UCH(*bufferptr++)];
  215.     *ptr++ = rescale[UCH(*bufferptr++)];
  216.     *ptr++ = rescale[UCH(*bufferptr++)];
  217.   }
  218.   return 1;
  219. }
  220.  
  221.  
  222. METHODDEF JDIMENSION
  223. get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  224. /* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
  225.  * In this case we just read right into the JSAMPLE buffer!
  226.  * Note that same code works for PPM and PGM files.
  227.  */
  228. {
  229.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  230.  
  231.   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
  232.     ERREXIT(cinfo, JERR_INPUT_EOF);
  233.   return 1;
  234. }
  235.  
  236.  
  237. METHODDEF JDIMENSION
  238. get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  239. /* This version is for reading raw-word-format PGM files with any maxval */
  240. {
  241.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  242.   register JSAMPROW ptr;
  243.   register U_CHAR * bufferptr;
  244.   register JSAMPLE *rescale = source->rescale;
  245.   JDIMENSION col;
  246.  
  247.   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
  248.     ERREXIT(cinfo, JERR_INPUT_EOF);
  249.   ptr = source->pub.buffer[0];
  250.   bufferptr = source->iobuffer;
  251.   for (col = cinfo->image_width; col > 0; col--) {
  252.     register int temp;
  253.     temp  = UCH(*bufferptr++);
  254.     temp |= UCH(*bufferptr++) << 8;
  255.     *ptr++ = rescale[temp];
  256.   }
  257.   return 1;
  258. }
  259.  
  260.  
  261. METHODDEF JDIMENSION
  262. get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  263. /* This version is for reading raw-word-format PPM files with any maxval */
  264. {
  265.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  266.   register JSAMPROW ptr;
  267.   register U_CHAR * bufferptr;
  268.   register JSAMPLE *rescale = source->rescale;
  269.   JDIMENSION col;
  270.  
  271.   if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
  272.     ERREXIT(cinfo, JERR_INPUT_EOF);
  273.   ptr = source->pub.buffer[0];
  274.   bufferptr = source->iobuffer;
  275.   for (col = cinfo->image_width; col > 0; col--) {
  276.     register int temp;
  277.     temp  = UCH(*bufferptr++);
  278.     temp |= UCH(*bufferptr++) << 8;
  279.     *ptr++ = rescale[temp];
  280.     temp  = UCH(*bufferptr++);
  281.     temp |= UCH(*bufferptr++) << 8;
  282.     *ptr++ = rescale[temp];
  283.     temp  = UCH(*bufferptr++);
  284.     temp |= UCH(*bufferptr++) << 8;
  285.     *ptr++ = rescale[temp];
  286.   }
  287.   return 1;
  288. }
  289.  
  290.  
  291. /*
  292.  * Read the file header; return image size and component count.
  293.  */
  294.  
  295. METHODDEF void
  296. start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  297. {
  298.   ppm_source_ptr source = (ppm_source_ptr) sinfo;
  299.   int c;
  300.   unsigned int w, h, maxval;
  301.   boolean need_iobuffer, use_raw_buffer, need_rescale;
  302.  
  303.   if (getc(source->pub.input_file) != 'P')
  304.     ERREXIT(cinfo, JERR_PPM_NOT);
  305.  
  306.   c = getc(source->pub.input_file); /* save format discriminator for a sec */
  307.  
  308.   /* fetch the remaining header info */
  309.   w = read_pbm_integer(cinfo, source->pub.input_file);
  310.   h = read_pbm_integer(cinfo, source->pub.input_file);
  311.   maxval = read_pbm_integer(cinfo, source->pub.input_file);
  312.  
  313.   if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
  314.     ERREXIT(cinfo, JERR_PPM_NOT);
  315.  
  316.   cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
  317.   cinfo->image_width = (JDIMENSION) w;
  318.   cinfo->image_height = (JDIMENSION) h;
  319.  
  320.   /* initialize flags to most common settings */
  321.   need_iobuffer = TRUE;        /* do we need an I/O buffer? */
  322.   use_raw_buffer = FALSE;    /* do we map input buffer onto I/O buffer? */
  323.   need_rescale = TRUE;        /* do we need a rescale array? */
  324.  
  325.   switch (c) {
  326.   case '2':            /* it's a text-format PGM file */
  327.     cinfo->input_components = 1;
  328.     cinfo->in_color_space = JCS_GRAYSCALE;
  329.     TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
  330.     source->pub.get_pixel_rows = get_text_gray_row;
  331.     need_iobuffer = FALSE;
  332.     break;
  333.  
  334.   case '3':            /* it's a text-format PPM file */
  335.     cinfo->input_components = 3;
  336.     cinfo->in_color_space = JCS_RGB;
  337.     TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
  338.     source->pub.get_pixel_rows = get_text_rgb_row;
  339.     need_iobuffer = FALSE;
  340.     break;
  341.  
  342.   case '5':            /* it's a raw-format PGM file */
  343.     cinfo->input_components = 1;
  344.     cinfo->in_color_space = JCS_GRAYSCALE;
  345.     TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
  346.     if (maxval > 255) {
  347.       source->pub.get_pixel_rows = get_word_gray_row;
  348.     } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
  349.       source->pub.get_pixel_rows = get_raw_row;
  350.       use_raw_buffer = TRUE;
  351.       need_rescale = FALSE;
  352.     } else {
  353.       source->pub.get_pixel_rows = get_scaled_gray_row;
  354.     }
  355.     break;
  356.  
  357.   case '6':            /* it's a raw-format PPM file */
  358.     cinfo->input_components = 3;
  359.     cinfo->in_color_space = JCS_RGB;
  360.     TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
  361.     if (maxval > 255) {
  362.       source->pub.get_pixel_rows = get_word_rgb_row;
  363.     } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
  364.       source->pub.get_pixel_rows = get_raw_row;
  365.       use_raw_buffer = TRUE;
  366.       need_rescale = FALSE;
  367.     } else {
  368.       source->pub.get_pixel_rows = get_scaled_rgb_row;
  369.     }
  370.     break;
  371.  
  372.   default:
  373.     ERREXIT(cinfo, JERR_PPM_NOT);
  374.     break;
  375.   }
  376.  
  377.   /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
  378.   if (need_iobuffer) {
  379.     source->buffer_width = (size_t) w * cinfo->input_components *
  380.       ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
  381.     source->iobuffer = (U_CHAR *)
  382.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  383.                   source->buffer_width);
  384.   }
  385.  
  386.   /* Create compressor input buffer. */
  387.   if (use_raw_buffer) {
  388.     /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
  389.     /* Synthesize a JSAMPARRAY pointer structure */
  390.     /* Cast here implies near->far pointer conversion on PCs */
  391.     source->pixrow = (JSAMPROW) source->iobuffer;
  392.     source->pub.buffer = & source->pixrow;
  393.     source->pub.buffer_height = 1;
  394.   } else {
  395.     /* Need to translate anyway, so make a separate sample buffer. */
  396.     source->pub.buffer = (*cinfo->mem->alloc_sarray)
  397.       ((j_common_ptr) cinfo, JPOOL_IMAGE,
  398.        (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
  399.     source->pub.buffer_height = 1;
  400.   }
  401.  
  402.   /* Compute the rescaling array if required. */
  403.   if (need_rescale) {
  404.     INT32 val, half_maxval;
  405.  
  406.     /* On 16-bit-int machines we have to be careful of maxval = 65535 */
  407.     source->rescale = (JSAMPLE *)
  408.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  409.                   (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
  410.     half_maxval = maxval / 2;
  411.     for (val = 0; val <= (INT32) maxval; val++) {
  412.       /* The multiplication here must be done in 32 bits to avoid overflow */
  413.       source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
  414.     }
  415.   }
  416. }
  417.  
  418.  
  419. /*
  420.  * Finish up at the end of the file.
  421.  */
  422.  
  423. METHODDEF void
  424. finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  425. {
  426.   /* no work */
  427. }
  428.  
  429.  
  430. /*
  431.  * The module selection routine for PPM format input.
  432.  */
  433.  
  434. GLOBAL cjpeg_source_ptr
  435. jinit_read_ppm (j_compress_ptr cinfo)
  436. {
  437.   ppm_source_ptr source;
  438.  
  439.   /* Create module interface object */
  440.   source = (ppm_source_ptr)
  441.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  442.                   SIZEOF(ppm_source_struct));
  443.   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
  444.   source->pub.start_input = start_input_ppm;
  445.   source->pub.finish_input = finish_input_ppm;
  446.  
  447.   return (cjpeg_source_ptr) source;
  448. }
  449.  
  450. #endif /* PPM_SUPPORTED */
  451.